﻿using System;
using System.Collections.Generic;
using Mbs.Collections;

namespace Mbs.Factories
{
    public interface IRegisterFactory<TKey, TOutput> : IFactory<TKey, TOutput>
    {
        void Register(TKey id, Func<TOutput> creator);
        void UnRegister(TKey id);
        bool HasRegister(TKey id);
    }

    public class RegisterFactory<TKey, TOutput> : FactoryBase<TKey, TOutput>, IRegisterFactory<TKey,TOutput>
    {
        private IMap<TKey, Func<TOutput>> Map;

        public RegisterFactory() : this(EqualityComparer<TKey>.Default) { }

        public RegisterFactory(IEqualityComparer<TKey> comparer)
        {
            Map = new ConcurrentMap<TKey, Func<TOutput>>(comparer);
        }

        public void Register(TKey id, Func<TOutput> creator)
        {
            if (id == null)
                throw new ArgumentNullException("id == null");

            if (Map.ContainsKey(id))
                throw new RepeatRegistrationException("Repeat registration exception for id:"+ id.ToString());

            if (creator == null)
                throw new ArgumentNullException("creator == null");

            Map[id] = creator;
        }

        public void UnRegister(TKey id)
        {
            if (id == null)
                throw new ArgumentNullException("id == null");

            if (!Map.ContainsKey(id))
                throw new Exception("id:["+id.ToString() +"] not exists");

            Map.Remove(id);
        }

        public bool HasRegister(TKey id)
        {
            return Map.ContainsKey(id);
        }

        public override TOutput Create(TKey id)
        {
            if (id == null)
                throw new ArgumentNullException("id == null");

            if (!Map.ContainsKey(id))
                throw new Exception("id:[" + id.ToString() + "] not exists");

            return Map[id]();

        }
    }
}
